package com.tanhua.admin.module.loginIndex.service.Impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.admin.module.loginIndex.mapper.AnalysisByDayMapper;
import com.tanhua.admin.module.loginIndex.pojo.AnalysisByDay;
import com.tanhua.admin.module.loginIndex.service.LoginIndexService;
import com.tanhua.admin.module.loginIndex.vo.LoginIndexVo;
import com.tanhua.common.mapper.UserInfoMapper;
import com.tanhua.common.mapper.UserMapper;
import com.tanhua.common.pojo.User;
import com.tanhua.common.vo.LoginParamVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author CZY
 * @Date 2021/4/20 10:44
 * @Version 1.0
 */
@Service
@Slf4j
public class LoginIndexServiceImpl implements LoginIndexService {

    private final static String dateStr = "2018-9-10";
    private final static Date date = DateUtil.parse(dateStr);
    private final static DecimalFormat df = new DecimalFormat("0%");//百分比

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private AnalysisByDayMapper analysisByDayMapper;

    /**
     * 统计用户概要信息
     *
     * @param token
     * @return
     */
    @Override
    public LoginIndexVo queryLogin(String token) {
        try {
            //校验token
            if (null == token) {
                return null;
            }

            //查询累计用户
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id");
            Integer cumulativeUsers = userMapper.selectCount(queryWrapper);

            //查询七天活跃用户
            QueryWrapper<AnalysisByDay> queryWrapperW = new QueryWrapper<>();
            queryWrapperW.between("record_date", DateUtil.offsetDay(date, -7), DateUtil.offsetDay(date, -1));
            List<AnalysisByDay> analysisByDays = analysisByDayMapper.selectList(queryWrapperW);
            Integer numWeek = 0;
            for (AnalysisByDay analysisByDay : analysisByDays) {
                numWeek += analysisByDay.getNumActive();
            }

            //查询一个月活跃用户数
            QueryWrapper<AnalysisByDay> queryWrapperM = new QueryWrapper<>();
            queryWrapperM.between("record_date", DateUtil.offsetMonth(date, -7), DateUtil.offsetDay(date, -1));
            List<AnalysisByDay> analysisByMonths = analysisByDayMapper.selectList(queryWrapperM);
            Integer numMonth = 0;
            for (AnalysisByDay analysisByMonth : analysisByMonths) {
                numMonth += analysisByMonth.getNumActive();
            }

            //查询当日用户数
            QueryWrapper<AnalysisByDay> queryOne = new QueryWrapper<>();
            queryOne.eq("record_date", date);
            AnalysisByDay analysisByDay = analysisByDayMapper.selectOne(queryOne);

            //查询昨日用户数
            QueryWrapper<AnalysisByDay> queryTerDayOne = new QueryWrapper<>();
            queryTerDayOne.eq("record_date", DateUtil.offsetDay(date, -1));
            AnalysisByDay analysisByTerDay = analysisByDayMapper.selectOne(queryTerDayOne);

            //信息填充
            LoginIndexVo loginIndexVo = new LoginIndexVo();

            loginIndexVo.setCumulativeUsers(cumulativeUsers); //累计用户
            loginIndexVo.setActivePassWeek(numWeek);///过去7天活跃用户
            loginIndexVo.setActivePassMonth(numMonth);//过去30天活跃用户


            loginIndexVo.setNewUsersToday(analysisByDay.getNumRegistered());//今日新增用户
            loginIndexVo.setNewUsersTodayRate(this.bdmToInt(analysisByDay.getNumRegistered(), analysisByTerDay.getNumRegistered()));//今日新增用户涨跌率,单位百分数,正数为涨,负数为跌

            loginIndexVo.setLoginTimesToday(analysisByDay.getNumLogin());//今日登录次数
            loginIndexVo.setLoginTimesTodayRate(this.bdmToInt(analysisByDay.getNumLogin(), analysisByTerDay.getNumLogin()));//今日登录次数涨跌率，单位百分数，正数为涨，负数为跌

            loginIndexVo.setActiveUsersToday(analysisByDay.getNumActive());//今日活跃用户数
            loginIndexVo.setActiveUsersTodayRate(this.bdmToInt(analysisByDay.getNumActive(), analysisByTerDay.getNumActive()));//今日活跃用户涨跌率，单位百分数，正数为涨，负数为跌

            loginIndexVo.setActiveUsersYesterday(analysisByTerDay.getNumActive());//昨日活跃用户
            loginIndexVo.setActiveUsersYesterdayRate(this.bdmToInt(analysisByDay.getNumActive(), analysisByTerDay.getNumActive()));//昨日活跃用户涨跌率，单位百分数，正数为涨，负数为

            loginIndexVo.setUseTimePassWeek(null);//过去7天平均日使用时长，单位秒

            return loginIndexVo;
        } catch (Exception e) {
            log.error("统计用户概要信息出错了~ LoginIndexServiceImpl", e);
        }


        return null;
    }

    /**
     * 新增,活跃用户,次日留存率实现
     *
     * @param token 指令
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param retentionRate 操作类型
     * @return
     */
    @Override
    public Map<String, Object[]> queryParam(String token, Long startTime, Long endTime, Integer retentionRate) {
        try {
            if (null == token) {
                return null;
            }

            return this.getMap(startTime, endTime, retentionRate);
        } catch (Exception e) {
            log.error("新增,活跃用户,次日留存率实现出错了");
        }

        return null;
    }

    /**
     * 分析分布统计查询
     * @param startTime 开始时间
     * @param endTime  结束时间
     * @return
     */
    @Override
    public Map<String, Object[]> queryInfo(Long startTime, Long endTime) {
        try {
            /*//将毫秒值转为常用日期格式
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String dateStart = sdf.format(startTime);
            String dateEnd = sdf.format(endTime);*/

            Map<String,Object[]> map=new HashMap<>();
            //行业
            List<LoginParamVo> industryDistribution=userInfoMapper.getIndustry();
            //年龄
            List<LoginParamVo> ageDistribution=userInfoMapper.getAge();
            //性别
            List<LoginParamVo> genderDistribution=userInfoMapper.getSexP();
            //省
            List<LoginParamVo> city = userInfoMapper.getCity();
            List<LoginParamVo> localDistribution= new ArrayList<>();
            //查询中截取的字符串为前两个,在此对字段进行一个补全
            for (LoginParamVo loginParamVo : city) {
                if ("黑龙".contains(loginParamVo.getTitle())){
                    loginParamVo.setTitle("黑龙江");
                }
                if ("内蒙".contains(loginParamVo.getTitle())){
                    loginParamVo.setTitle("内蒙古");
                }
                if ("南海".contains(loginParamVo.getTitle())){
                    loginParamVo.setTitle("南海诸岛");
                }
                localDistribution.add(loginParamVo);
            }
            //数据库中没有南海诸岛的用户,在此手动添加一个假数据
            localDistribution.add(new LoginParamVo("南海诸岛",0));
            //七大区
            List<LoginParamVo> cityArea = userInfoMapper.getCityArea();
            List<LoginParamVo> localTotal=new ArrayList<>();
            Integer hz =0;
            Integer hb =0;
            Integer hn =0;
            Integer hd =0;
            Integer xb =0;
            Integer db =0;
            Integer xn =0;


            //华北(北京市,天津市,河北省,内蒙古自治区,山西省)
            List<String> HB=new ArrayList<>();
            Collections.addAll(HB,"北京市","天津市","河北省","内蒙古自治区","山西省");

            //华东(上海市,浙江省,江苏省,安徽省,山东省,江西省,台湾省,福建省,南京市)
            List<String> HD=new ArrayList<>();
            Collections.addAll(HD,"上海市","浙江省","江苏省","安徽省","山东省","江西省","台湾省","福建省","南京市");

            //华南(广东省,广西省,海南省,澳门特别行政区,香港特别行政区)
            List<String> HN=new ArrayList<>();
            Collections.addAll(HN,"广东省","广西省","海南省","澳门特别行政区","香港特别行政区");

            //华中(河南省,湖北省,湖南省)
            List<String> HZ=new ArrayList<>();
            Collections.addAll(HZ,"河南省","湖北省","湖南省");

            //西南(四川省,重庆市,西藏自治区,贵州省,云南省)
            List<String> XN=new ArrayList<>();
            Collections.addAll(XN,"四川省","重庆市","西藏自治区","贵州省","云南省");

            //东北(辽宁省,吉林省,黑龙江省)
            List<String> DB=new ArrayList<>();
            Collections.addAll(DB,"辽宁省","吉林省","黑龙江省");

            //西北(陕西省,宁夏回族自治区,青海省,甘肃省,新疆维吾尔自治区)
            List<String> XB=new ArrayList<>();
            Collections.addAll(XB,"陕西省","宁夏回族自治区","青海省","甘肃省","新疆维吾尔自治区");

            //统计地区人数
            for (LoginParamVo loginParamVo : cityArea) {
                if (HZ.contains(loginParamVo.getTitle())) {
                    hz+=loginParamVo.getAmount();
                    continue;//结束当前这次循环提高效率
                }

                if (HD.contains(loginParamVo.getTitle())) {
                    hd+=loginParamVo.getAmount();
                    continue;
                }

                if (HN.contains(loginParamVo.getTitle())) {
                    hn+=loginParamVo.getAmount();
                    continue;
                }

                if (HB.contains(loginParamVo.getTitle())) {
                    hb+=loginParamVo.getAmount();
                    continue;
                }

                if (XB.contains(loginParamVo.getTitle())) {
                    xb+=loginParamVo.getAmount();
                    continue;
                }

                if (DB.contains(loginParamVo.getTitle())) {
                    db+=loginParamVo.getAmount();
                    continue;
                }

                xn+=loginParamVo.getAmount();
            }

            localTotal.add(new LoginParamVo("华中地区",hz));
            localTotal.add(new LoginParamVo("华北地区",hb));
            localTotal.add(new LoginParamVo("华南地区",hn));
            localTotal.add(new LoginParamVo("华东地区",hd));
            localTotal.add(new LoginParamVo("西北地区",xb));
            localTotal.add(new LoginParamVo("东北地区",db));
            localTotal.add(new LoginParamVo("西南地区",xn));

            map.put("industryDistribution",industryDistribution.toArray());
            map.put("ageDistribution",ageDistribution.toArray());
            map.put("genderDistribution",genderDistribution.toArray());
            map.put("localDistribution",localDistribution.toArray());
            map.put("localTotal",localTotal.toArray());
            return map;
        }catch (Exception e){
            log.error("分布统计出错了",e);
        }
        return null;
    }

    private Map<String, Object[]> getMap(Long startTime, Long endTime, Integer retentionRate) {
        //将毫秒值转为常用日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStart = sdf.format(startTime);
        String dateEnd = sdf.format(endTime);

        //查询新增用户数
        QueryWrapper<AnalysisByDay> thisQueryWrapper = new QueryWrapper<>();
        thisQueryWrapper.between("record_date", dateStart, dateEnd);
        Object[] thisArray = this.getArray(analysisByDayMapper.selectList(thisQueryWrapper), retentionRate);

        QueryWrapper<AnalysisByDay> lastQueryWrapper = new QueryWrapper<>();
        //相对于传入的时间做时间量的偏移
        lastQueryWrapper.between("record_date", DateUtil.offsetMonth(new Date(startTime), -12), DateUtil.offsetMonth(new Date(endTime), -12));
        Object[] lastArray = this.getArray(analysisByDayMapper.selectList(lastQueryWrapper), retentionRate);

        Map<String, Object[]> map = new HashMap<>();
        map.put("thisYear", thisArray);
        map.put("lastYear", lastArray);
        return map;
    }

    /**
     * 集合转数组
     *
     * @param list
     * @return
     */
    private Object[] getArray(List<AnalysisByDay> list, Integer retentionRate) {
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        if (101 == retentionRate) {
            List<LoginParamVo> lp = new ArrayList<>();
            for (AnalysisByDay analysisByDay : list) {
                LoginParamVo loginParam = new LoginParamVo();
                loginParam.setTitle(analysisByDay.getRecordDate());
                loginParam.setAmount(analysisByDay.getNumRegistered());
                lp.add(loginParam);
            }
            return lp.toArray();
        }

        if (102 == retentionRate) {
            List<LoginParamVo> lp = new ArrayList<>();
            for (AnalysisByDay analysisByDay : list) {
                LoginParamVo loginParam = new LoginParamVo();
                loginParam.setTitle(analysisByDay.getRecordDate());
                loginParam.setAmount(analysisByDay.getNumActive());
                lp.add(loginParam);
            }
            return lp.toArray();
        }

        if (103 == retentionRate) {
            List<LoginParamVo> lp = new ArrayList<>();
            for (AnalysisByDay analysisByDay : list) {
                LoginParamVo loginParam = new LoginParamVo();
                loginParam.setTitle(analysisByDay.getRecordDate());
                //todo:计算次日留存率暂时使用假数据,如有时间重新设计生成表
                BigDecimal s = new BigDecimal(analysisByDay.getNumRegistered() - 100);
                int divide = s.divide(new BigDecimal(analysisByDay.getNumRegistered()), 2, BigDecimal.ROUND_FLOOR).multiply(new BigDecimal(100)).intValue();
                if (divide < 0) {
                    divide = 0;
                }
                loginParam.setAmount(divide);
                lp.add(loginParam);
            }
            return lp.toArray();
        }

        return null;
    }

    /**
     * 计算环比,转换类型
     *
     * @param day    当天的数据
     * @param terDay 昨天的数据
     * @return
     */
    private Integer bdmToInt(Integer day, Integer terDay) {
        Integer dividend = day - terDay;
        if (0 == dividend) {
            return 0;
        }
        BigDecimal bDividend = new BigDecimal(dividend);
        BigDecimal divide = bDividend.divide(new BigDecimal(terDay), 2, BigDecimal.ROUND_FLOOR);
        return divide.multiply(new BigDecimal(100)).intValue();
    }
}
